#include "./../Headers/color.h"

#ifdef ALLOW_DEBUG
#define DEBUG_VIS_COLOR
#endif
#ifdef ALLOW_FILE_FEEDBACK
#define FILE_VIS_COLOR
#endif

namespace Visual {
		
	const double Color::max_comp = 1.0;

	bool Color::create(){
		coord = (double*) malloc( spt_dim * sizeof( sint ) );
		if( coord == NULL )
			return false;
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] = 0.0;
		return true;
	};
	void Color::copy( const Color &original ){
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] = original.coord[i];
	};
	void Color::free(){
		delete coord;
	}
		
	Color::Color ( const double &red, const double &green, const double &blue, const double &alpha ):
		coord( NULL ) {
		if( !create() ){
			cout << "Couldn't create coordinates array!" << endl;
			exit(-1);
		}
		coord[R] = red; coord[G] = green; coord[B] = blue; coord[A] = alpha;
	};
	Color::Color ( const Color &original ):
		coord( NULL ) {
		if( !create() ){
			cout << "Couldn't create coordinates array!" << endl;
			exit(-1);
		}
		copy( original );
	};
	Color::~Color(){
		#ifdef DEBUG_VIS_COLOR
			debug_function_info( "Destructor", "Color", &(*this), sizeof(*this) );
		#endif
		free();
	};
	
	///*
	//	0 <= H < 360, 0.0 <= S <= 1.0, 0.0 <= V <= 1.0

	//	H_i = Lower( H / 60 ) % 6
	//	f = ( H / 60 ) - H_i
	//	p = V * ( 1 - S )
	//	q = V * ( 1 - f*S )
	//	t = V * ( 1 - ( 1 - f )*S )

	//	if H_i == 0 -> R = V, G = t, B = p
	//	if H_i == 1 -> R = q, G = V, B = p
	//	if H_i == 2 -> R = p, G = V, B = t
	//	if H_i == 3 -> R = p, G = q, B = V
	//	if H_i == 4 -> R = t, G = p, B = V
	//	if H_i == 5 -> R = V, G = p, B = q
	//*/
	//void Color::setColorHSV( const double &h, const double &s, const double &v ) {
	//	using namespace Mathematics;
	//	sint temp = max_comp-1;
	//	sint h_i = Low( h/60.0 ) % 6;
	//	sint f = Round( temp * ( h / 60.0 ) - h_i );
	//	sint p = Round( temp * v * ( 1 - s ) );
	//	sint q = Round( temp * v * ( 1 - f*s ) );
	//	sint t = Round( temp * v * ( 1 - ( 1 - f )*s ) );
	//		
	//	switch( h_i ){
	//	case 0:
	//		coord[R] = Round( temp * v );	coord[G] = t;	coord[B] = p;
	//		break;
	//	case 1:
	//		coord[R] = q;	coord[G] = Round( temp * v );	coord[B] = p;
	//		break;
	//	case 2:
	//		coord[R] = p;	coord[G] = Round( temp * v );	coord[B] = t;
	//		break;
	//	case 3:
	//		coord[R] = p;	coord[G] = q;	coord[B] = Round( temp * v );
	//		break;
	//	case 4:
	//		coord[R] = t;	coord[G] = p;	coord[B] = Round( temp * v );
	//		break;
	//	case 5:
	//		coord[R] = Round( temp * v );	coord[G] = p;	coord[B] = q;
	//		break;
	//	}
	//	verify();
	//};

	Color& Color::operator = ( const Color &col ) {
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] = col.coord[i];
		return (*this);
	};
	Color Color::operator + ( const Color &col ) const {
		Color result;
		for( usint i = 0; i < spt_dim; ++i )
			result.coord[i] = coord[i] + col.coord[i];
		result.verify();
		return result;
	};
	Color& Color::operator += ( const Color &col ) {
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] += col.coord[i];
		verify();
		return (*this);
	};
	Color Color::operator - ( const Color &col ) const {
		Color result;
		for( usint i = 0; i < spt_dim; ++i )
			result.coord[i] = coord[i] - col.coord[i];
		result.verify();
		return result;
	};
	Color& Color::operator -= ( const Color &col ) {
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] -= col.coord[i];
		verify();
		return (*this);
	};
	Color Color::operator * ( const double &value ) const {
		using namespace Mathematics;
		Color result;
		for( usint i = 0; i < spt_dim; ++i )
			result.coord[i] = Round( coord[i] * value );
		result.verify();
		return result;
	};
	Color& Color::operator *= ( const double &value ) {
		using namespace Mathematics;
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] = Round( coord[i] * value );
		verify();
		return (*this);
	};
	Color Color::operator / ( const double &value ) const {
		using namespace Mathematics;
		if( value == 0.0 )
			throw DivisionByZeroException<Color>( "Invalid Division", (*this) );
		Color result;
		for( usint i = 0; i < spt_dim; ++i )
			result.coord[i] = Round( coord[i] / value );
		result.verify();
		return result;
	};
	Color& Color::operator /= ( const double &value ) {
		using namespace Mathematics;
		if( value == 0.0 )
			throw DivisionByZeroException<Color>( "Invalid Division", (*this) );
		for( usint i = 0; i < spt_dim; ++i )
			coord[i] = Round( coord[i] / value );
		verify();
		return (*this);
	};
		
	bool Color::filePrint( FILE *parq ) const {
		#ifdef FILE_VIS_COLOR
			fb_print( "Color" );
		#endif
		if( fprintf( parq, "%d,%d,%d\n", coord[0], coord[1], coord[2] ) < 3){
			return false;
		}
		return true;
	};
		
	double* Color::toPointerd() const {
		double *result = NULL;
		result = (double*) malloc( spt_dim * sizeof(double) );
		if( result == NULL ){
			cout << "Couldn't allocate memory!" << endl;
			exit(-1);
		}
		for( usint i = 0; i < spt_dim; ++i )
			result[i] = coord[i];
		return result;
	};
	float* Color::toPointerf() const {
		float *result = NULL;
		result = (float*) malloc( spt_dim * sizeof(float) );
		if( result == NULL ){
			cout << "Couldn't allocate memory!" << endl;
			exit(-1);
		}
		for( usint i = 0; i < spt_dim; ++i )
			result[i] = (float) coord[i];
		return result;
	};
		
	//void Color::test(){
	//	cout << endl << "---Test:Color---" << endl;
	//		
	//	cout << "Correction mode: " << correction << endl;
	//		
	//	Color col1( 100, 255, 0 );
	//	Color col2( 0, 128, 128 );
	//		
	//	cout << "col1: " << col1 << endl;
	//	cout << "col2: " << col2 << endl;
	//		
	//	cout << "col1[0]: " << col1[0] << endl;
	//	cout << "col1[R]: " << col1[R] << endl;
	//	cout << "col1[G]: " << col1[G] << endl;
	//	cout << "col1[B]: " << col1[B] << endl;
	//		
	//	cout << "col1 + col2: " << col1 + col2 << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 - col2: " << col1 - col2 << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 * 2.5: " << col1 * 2.5 << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 / 4.0: " << col1 / 4.0 << endl;
	//	cout << "col1: " << col1 << endl;
	//		
	//	cout << "col1 += col2: " << (col1 += col2) << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 -= col2: " << (col1 -= col2) << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 *= 2.5: " << (col1 *= 2.5) << endl;
	//	cout << "col1: " << col1 << endl;
	//	cout << "col1 /= 4.0: " << (col1 /= 4.0) << endl;
	//	cout << "col1: " << col1 << endl;
	//		
	//	col1.setColorRGB( 128, 0, 255 );
	//	cout << "col1.setColorRGB( 128, 0, 255 );" << endl;
	//	cout << "col1: " << col1 << endl;
	//	col1.setColorCMY( 128, 0, 255 );
	//	cout << "col1.setColorCMY( 128, 0, 255 );" << endl;
	//	cout << "col1: " << col1 << endl;
	//	col1.setColorHSV( 180.0, 0.5, 0.8 );
	//	cout << "col1.setColorHSV( 180.0, 0.5, 0.8 );" << endl;
	//	cout << "col1: " << col1 << endl;
	//		
	//	cout << endl << "---TestEnd---" << endl;
	//};
		
};
